package com.xuqi.W3;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * W3Request queue to hold requests to be executed in the future.
 */
public class W3RequestQueue {

	/**
	 * constants
	 */
	public static final int			INVALID_QUEUE_ID	= 0;
	private static final int		MINIMUM_QUEUE_ID	= INVALID_QUEUE_ID + 1;
	private static final int		MAXIMUM_QUEUE_ID	= Integer.MAX_VALUE;

	/**
	 * Class variables
	 */
	private static int				s_iQueueID		= MINIMUM_QUEUE_ID;		///< for generating an unique queue ID.

	/**
	 * Instance variables.
	 */
	private int						m_iMaxCapacity	= 0;
	private List<W3ThreadTask>		m_lstTaskList	= null;
	final private ReentrantLock		m_cLock			= new ReentrantLock();
	final private Condition			m_cSigNonEmpty	= m_cLock.newCondition();

	public W3RequestQueue() {
		this(1024);
	}

	public W3RequestQueue(int iMaxCapacity) {
		m_iMaxCapacity	= iMaxCapacity;
		m_lstTaskList	= new LinkedList<W3ThreadTask>(); 
	}

	/**
	 * Add a task into the queue.
	 * 
	 * @param task	: the task to be executed.
	 * 
	 * @return	Queue id of the task if successful, otherwise -1 will be returned.
	 */
	public int push(W3ThreadTask task) {
		int iQueueID = -1;

		synchronized(W3RequestQueue.class) {
			iQueueID = s_iQueueID;
			if ( s_iQueueID >= MAXIMUM_QUEUE_ID ) {
				s_iQueueID = MINIMUM_QUEUE_ID;
			}
			else {
				++s_iQueueID;
			}
		}

		m_cLock.lock();
		try {
			if ( m_lstTaskList.size() >= m_iMaxCapacity ) {
				iQueueID = -1;
			}
			else if ( !m_lstTaskList.add(task) ) {
				iQueueID = -1;
			}
			else {
				task.setQueueID(iQueueID);
				m_cSigNonEmpty.signal();
			}
		}
		finally {
			m_cLock.unlock();
		}

		return iQueueID;
	}

	public W3ThreadTask pop() throws InterruptedException {
		return pop(Integer.MAX_VALUE);
	}

	public W3ThreadTask pop(int seconds) throws InterruptedException {
		W3ThreadTask task = null;

		try {
			synchronized(this) {
				Iterator<W3ThreadTask> it = m_lstTaskList.iterator();
				while ( it.hasNext() ) {
					W3ThreadTask next = it.next();
					if ( null == task || next.getPriority() >= task.getPriority() ) {
						task = next;
					}
				}
				if ( null != task ) {
					m_lstTaskList.remove(task);
				}
			}

			if ( null == task && seconds > 0 ) {
				m_cLock.lock();
				try {
					if ( Integer.MAX_VALUE == seconds ) {
						m_cSigNonEmpty.await();
					}
					else {
						m_cSigNonEmpty.await(seconds, TimeUnit.SECONDS);
					}
				}
				finally {
					m_cLock.unlock();
				}
				return pop(0);
			}
		} catch (InterruptedException e) {
			/* do nothing */
			throw e;
		}

		return task;	
	}
	
	public synchronized void remove(int iQueueID) {
		Iterator<W3ThreadTask> it = m_lstTaskList.iterator();
		while ( it.hasNext() ) {
			W3ThreadTask task = it.next();
			if ( task.getQueueID() == iQueueID ) {
				it.remove();
				break;
			}
		}
	}
}
